package com.zingrow.common.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.PropertyFilter;

/**
 * @Description: Json处理器<br>
 * @author：肖春平 576851277@qq.com @date：2014-5-15 上午9:20:19
 * @version
 */
@SuppressWarnings("rawtypes")
public class JsonHelper {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface NotJsonField {

    }

    private static Logger log = LoggerFactory.getLogger(JsonHelper.class);

    /**
     * 将不含日期时间格式的Java对象系列化为Json资料格式
     * 
     * @param pObject
     *            传入的Java对象
     * @return
     */
    public static final String encodeObject2Json(Object pObject) {
        String jsonString = "[]";
        if (StringUtil.isNullOrEmpty(pObject)) {
            // log.warn("传入的Java对象为空,不能将其序列化为Json资料格式.请检查!");
        } else {
            if (pObject instanceof ArrayList) {
                JSONArray jsonArray = JSONArray.fromObject(pObject);
                jsonString = jsonArray.toString();
            } else {
                JSONObject jsonObject = JSONObject.fromObject(pObject);
                jsonString = jsonObject.toString();
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 将不含日期时间格式的Java对象系列化为Json资料格式 add by chenweilong
     * 
     * @param pObject
     *            传入的Java对象 filterObjectArray是包含需要过滤属性的对应
     * @return
     */
    public static final String encodeObject2Json(Object pObject, Object... filterObjectArray) {
        String jsonString = "[]";
        if (StringUtil.isNullOrEmpty(pObject)) {
            // log.warn("传入的Java对象为空,不能将其序列化为Json资料格式.请检查!");
        } else {
            JsonConfig cfg = createJsonConfigByAnnotation(filterObjectArray);

            if (pObject instanceof ArrayList) {
                JSONArray jsonArray = JSONArray.fromObject(pObject, cfg);
                jsonString = jsonArray.toString();
            } else {
                JSONObject jsonObject = JSONObject.fromObject(pObject, cfg);
                jsonString = jsonObject.toString();
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 将含有日期时间格式的Java对象系列化为Json资料格式<br>
     * Json-Lib在处理日期时间格式是需要实现其JsonValueProcessor接口,所以在这里提供一个重载的方法对含有<br>
     * 日期时间格式的Java对象进行序列化
     * 
     * @param pObject
     *            传入的Java对象
     * @return
     */
    public static final String encodeObject2Json(Object pObject, String pFormatString) {
        String jsonString = "[]";
        if (StringUtil.isNullOrEmpty(pObject)) {
            // log.warn("传入的Java对象为空,不能将其序列化为Json资料格式.请检查!");
        } else {
            JsonConfig cfg = new JsonConfig();
            cfg.registerJsonValueProcessor(java.sql.Timestamp.class, new JsonValueProcessorImpl(pFormatString));
            cfg.registerJsonValueProcessor(java.util.Date.class, new JsonValueProcessorImpl(pFormatString));
            cfg.registerJsonValueProcessor(java.sql.Date.class, new JsonValueProcessorImpl(pFormatString));
            if (pObject instanceof ArrayList) {
                JSONArray jsonArray = JSONArray.fromObject(pObject, cfg);
                jsonString = jsonArray.toString();
            } else {
                JSONObject jsonObject = JSONObject.fromObject(pObject, cfg);
                jsonString = jsonObject.toString();
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 将含有日期时间格式的Java对象系列化为Json资料格式<br>
     * Json-Lib在处理日期时间格式是需要实现其JsonValueProcessor接口,所以在这里提供一个重载的方法对含有<br>
     * 日期时间格式的Java对象进行序列化 add by chenweilong
     * 
     * @param pObject
     *            传入的Java对象
     * @return
     */
    public static final String encodeObject2Json(Object pObject, String pFormatString, Object... filterObjectArray) {
        String jsonString = "[]";
        if (StringUtil.isNullOrEmpty(pObject)) {
            // log.warn("传入的Java对象为空,不能将其序列化为Json资料格式.请检查!");
        } else {

            JsonConfig cfg = createJsonConfigByAnnotation(filterObjectArray);

            cfg.registerJsonValueProcessor(java.sql.Timestamp.class, new JsonValueProcessorImpl(pFormatString));
            cfg.registerJsonValueProcessor(java.util.Date.class, new JsonValueProcessorImpl(pFormatString));
            cfg.registerJsonValueProcessor(java.sql.Date.class, new JsonValueProcessorImpl(pFormatString));

            if (pObject instanceof ArrayList) {
                JSONArray jsonArray = JSONArray.fromObject(pObject, cfg);
                jsonString = jsonArray.toString();
            } else {
                JSONObject jsonObject = JSONObject.fromObject(pObject, cfg);
                jsonString = jsonObject.toString();
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    private static JsonConfig createJsonConfigByAnnotation(Object... filterObjectArray) {

        JsonConfig cfg = new JsonConfig();

        if (filterObjectArray.length > 0) {

        }

        final List<String> needToIgnoreProperty = new ArrayList<String>();

        for (Object obj : filterObjectArray) {

            Field[] fields = obj.getClass().getDeclaredFields();

            for (Field field : fields) {
                System.out.println(field.getName());
                NotJsonField needToIgnoreField = field.getAnnotation(NotJsonField.class);

                if (needToIgnoreField != null) {
                    needToIgnoreProperty.add(field.getName());
                }

            }
        }

        if (needToIgnoreProperty.size() > 0) {
            cfg.setJsonPropertyFilter(new PropertyFilter() {
                @Override
                public boolean apply(Object source, String name, Object value) {
                    if (needToIgnoreProperty.contains(name)) {
                        return true;
                    }
                    return false;
                }
            });
        }

        return cfg;
    }

    /**
     * 将分页信息压入JSON字符串 此类内部使用,不对外暴露
     * 
     * @param JSON字符串
     * @param totalCount
     * @return 返回合并后的字符串
     */
    @SuppressWarnings("unused")
    private static String encodeJson2PageJson(String jsonString, Integer totalCount) {
        jsonString = "{TOTALCOUNT:" + totalCount + ", ROOT:" + jsonString + "}";
        if (log.isDebugEnabled()) {
            log.debug("合并后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 直接将List转为分页所需要的Json资料格式
     * 
     * @param list
     *            需要编码的List对象
     * @param totalCount
     *            记录总数
     * @param pDataFormat
     *            时间日期格式化,传null则表明List不包含日期时间属性
     */
    public static final String encodeList2PageJson(List list, Integer totalCount, String dataFormat) {
        String subJsonString = "";
        if (StringUtil.isNullOrEmpty(dataFormat)) {
            subJsonString = encodeObject2Json(list);
        } else {
            subJsonString = encodeObject2Json(list, dataFormat);
        }
        String jsonString = "{TOTALCOUNT:" + totalCount + ", ROOT:" + subJsonString + "}";
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 直接将List转为分页所需要的Json资料格式
     * 
     * @param list
     *            需要编码的List对象
     * @param totalCount
     *            记录总数
     * @param pDataFormat
     *            时间日期格式化,传null则表明List不包含日期时间属性
     */
    public static final String encodeList2PageJsonJoffice(List list, Integer totalCount, String dataFormat) {
        String subJsonString = "";
        if (StringUtil.isNullOrEmpty(dataFormat)) {
            subJsonString = encodeObject2Json(list);
        } else {
            subJsonString = encodeObject2Json(list, dataFormat);
        }
        String jsonString = "{success:true,totalCounts:" + totalCount + ", result:" + subJsonString + "}";
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 将数据系列化为表单数据填充所需的Json格式
     * 
     * @param pObject
     *            待系列化的对象
     * @param pFormatString
     *            日期时间格式化,如果为null则认为没有日期时间型字段
     * @return
     */
    public static String encodeDto2FormLoadJson(Map pDto, String pFormatString) {
        String jsonString = "";
        String sunJsonString = "";
        if (StringUtil.isNullOrEmpty(pFormatString)) {
            sunJsonString = encodeObject2Json(pDto);
        } else {
            sunJsonString = encodeObject2Json(pDto, pFormatString);
        }
        jsonString = "{success:" + (StringUtil.isNullOrEmpty(pDto.get("success")) ? "true" : pDto.get("success"))
                + ",data:" + sunJsonString + "}";
        if (log.isDebugEnabled()) {
            log.debug("序列化后的JSON资料输出:\n" + jsonString);
        }
        return jsonString;
    }

    /**
     * 将单一Json对象解析为DTOJava对象
     * 
     * @param jsonString
     *            简单的Json对象
     * @return dto
     */
    public static Map parseSingleJson2Dto(String jsonString) {
        Map dto = new HashMap();
        if (StringUtil.isNullOrEmpty(jsonString)) {
            return dto;
        }
        JSONObject jb = JSONObject.fromObject(jsonString);
        dto = (Map) JSONObject.toBean(jb, HashMap.class);
        return dto;
    }

    /**
     * 将复杂Json资料格式转换为List对象
     * 
     * @param jsonString
     *            复杂Json对象,格式必须符合如下契约<br>
     *            {"1":{"name":"托尼.贾","age":"27"},
     *            "2":{"name":"甄子丹","age":"72"}}
     * @return List
     */
    @SuppressWarnings("unchecked")
    public static List parseJson2List(String jsonString) {
        List list = new ArrayList();
        JSONObject jbJsonObject = JSONObject.fromObject(jsonString);
        Iterator iterator = jbJsonObject.keySet().iterator();
        while (iterator.hasNext()) {
            Map dto = parseSingleJson2Dto(jbJsonObject.getString(iterator.next().toString()));
            list.add(dto);
        }
        return list;
    }

}
